package com.jifeng.api.crud.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jifeng.api.constant.HttpStatusEnum;
import com.jifeng.api.crud.constant.FieldConstant;
import com.jifeng.api.crud.dao.OrderDao;
import com.jifeng.api.crud.entity.FeeConfigEntity;
import com.jifeng.api.crud.entity.OrderEntity;
import com.jifeng.api.crud.entity.TerminalEntity;
import com.jifeng.api.crud.service.FeeConfigService;
import com.jifeng.api.crud.service.OrderService;
import com.jifeng.api.crud.service.TerminalService;
import com.jifeng.api.crud.utils.CheckParamsRs;
import com.jifeng.api.utils.*;
import com.jifeng.api.vo.ReqRentVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.*;


@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    FeeConfigService feeConfigService;

    @Autowired
    CheckParamsRs checkParamsRs;

    @Autowired
    TerminalService terminalService;

    @Autowired
    SendSmsUtils sendSmsUtils;

    public String getRequestUrl() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest().getRequestURI();
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public R returnDevice(ReqRentVo params) {
        String terminalId = "";
        try {
            terminalId = params.getTerminalId();
            String deviceId = params.getDeviceId();

            /**
             * 校验 机柜编号 和 手机号格式
             */
            boolean checkIotRs = checkParamsRs.checkIot(terminalId);
            if (!checkIotRs) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), "机柜编号格式错误");
                return R.error("Incorrect terminal_id");
            }

            /**
             * 查询机柜信息
             */
            TerminalEntity terminalEntity = terminalService.getOne(new QueryWrapper<TerminalEntity>().eq(FieldConstant.T_TERMINAL_IOT, terminalId));
            if (terminalEntity == null) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), "不存在该机柜");
                return R.error("Invalid terminal");
            }

            /**
             * 查看是否有已经租赁或未清算的订单
             */
            List<OrderEntity> orderEntities = this.list(new QueryWrapper<OrderEntity>()
                    .eq(FieldConstant.T_ORDER_DEVICE_ID, deviceId)
                    .and(Wrapper -> Wrapper.eq(FieldConstant.T_ORDER_STATUS, 4)
                            .or()
                            .eq(FieldConstant.T_ORDER_STATUS, 6))
            );
            if (orderEntities.isEmpty()) {
                terminalEntity.setRentState(0);
                boolean update = terminalService.updateById(terminalEntity);
                if (!update) {
                    // TODO: 2020/9/26  往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新机柜状态失败");
                }

                /**
                 * 当未找到订单时调用下位机
                 */
                boolean backDeviceRs = HttpUtils.rentBackDevice(terminalId, "0");
                if (!backDeviceRs) {
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "设备未连接");
                    return R.error("Device not connected");
                }

                log.warn("path：{}，errMsg：{}", getRequestUrl(), "没有已经租赁或未清算的订单");
                return R.error(404, "no have using order");
            }

            OrderEntity orderEntity = orderEntities.get(orderEntities.size() - 1);
            orderEntity.setComState(9);
            orderEntity.setState(5);
            orderEntity.setRevTime(new Date());
            orderEntity.setEndFeeTime(new Date());
            boolean updateOrderRs = this.updateById(orderEntity);
            if (!updateOrderRs) {
                terminalEntity.setRentState(0);
                boolean update = terminalService.updateById(terminalEntity);
                if (!update) {
                    // TODO: 2020/9/26  往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新机柜状态失败");
                }
                // TODO: 2020/9/26 往更新失败表中插入记录
                log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新订单失败");
                return R.error("Fail update order");
            }

            /**
             * 计算最终费用
             */
            Date startFeeTime = orderEntity.getStartFeeTime();
            Date endFeeTime = orderEntity.getEndFeeTime();
            FeeConfigEntity feeConfigEntity = feeConfigService.getById(1);
            Integer baseFee = feeConfigEntity.getBaseFee();
            Integer baseHour = feeConfigEntity.getBaseHour();
            Integer extFee = feeConfigEntity.getExtFee();
            Integer maxFee = feeConfigEntity.getMaxFee();

            // 超出费用
            int extraCost = RegexUtils.orderIsOvertime(startFeeTime, endFeeTime, baseHour, extFee);

            /**
             * 订单超时
             */
            if (extraCost != 0) {
                /**
                 * 计算使用小时和分钟
                 */
                int minuteSum = new Long(DateUtil.between(startFeeTime, endFeeTime, DateUnit.MINUTE)).intValue();
                int hour = minuteSum / 60;
                int minute = minuteSum - (hour * 60);

                /**
                 * 发送短信，提示欠费
                 */
                sendSmsUtils.sendSms(orderEntity.getMobile(), 1, hour, minute, extraCost / 100, 0, 0);

                /**
                 * 判断费用是否超出最大费用
                 */
                int needPaidFee = extraCost + baseFee;
                if (needPaidFee > maxFee) {
                    needPaidFee = 10000;
                }

                /**
                 * 修改订单信息
                 */
                orderEntity.setFee(needPaidFee);
                orderEntity.setComState(10);
                orderEntity.setState(6);
                boolean updateOrderRs2 = this.updateById(orderEntity);
                if (!updateOrderRs2) {
                    // TODO: 2020/9/26 往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新订单失败");
                    return R.error("Fail update order");
                }

                /**
                 * 将机柜设置为空闲状态
                 */
                terminalEntity.setRentState(0);
                boolean update = terminalService.updateById(terminalEntity);
                if (!update) {
                    // TODO: 2020/9/26  往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新机柜状态失败");
                }

                /**
                 * 调用下位机欠费成功归还
                 */
                boolean backDeviceRs = HttpUtils.rentBackDevice(terminalId, "2");
                if (!backDeviceRs) {
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "设备未连接");
                    return R.error("Device not connected");
                }
            } else {

                /**
                 * 订单未超时
                 */
                orderEntity.setComState(12);
                orderEntity.setState(7);
                boolean updateOrderRs2 = this.updateById(orderEntity);
                if (!updateOrderRs2) {
                    // TODO: 2020/9/26 往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新订单失败");
                    return R.error("Fail update order");
                }

                /**
                 * 将机柜设置为空闲状态
                 */
                terminalEntity.setRentState(0);
                boolean update = terminalService.updateById(terminalEntity);
                if (!update) {
                    // TODO: 2020/9/26  往更新失败表中插入记录
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新机柜状态失败");
                }

                /**
                 * 调用下位机成功归还
                 */
                boolean backDeviceRs = HttpUtils.rentBackDevice(terminalId, "1");
                if (!backDeviceRs) {
                    log.warn("path：{}，errMsg：{}", getRequestUrl(), "设备未连接");
                    return R.error("Device not connected");
                }
            }

            return R.ok();
        } catch (Exception e) {
//            TerminalEntity terminalEntity = new TerminalEntity();
//            terminalEntity.setIot(terminalId);
//            terminalEntity.setRentState(0);
//            boolean update = terminalService.updateById(terminalEntity);
//            if (!update) {
//                // TODO: 2020/9/26  往更新失败表中插入记录
//                log.warn("path：{}，errMsg：{}", getRequestUrl(), "更新机柜状态失败");
//            }
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.error(500, "System is busy");
        }
    }

    @Override
    public R checkFee(ReqRentVo params) {
        try {
            String terminalId = params.getTerminalId();
            String mobile = params.getMobile();
            String orderId = params.getNumber();
            log.info("path：{}，orderId：{}", getRequestUrl(), orderId);

            /**
             * 校验 机柜编号 和 手机号格式
             */
            boolean checkIotAndMobileRs = checkParamsRs.checkIotAndMobile(terminalId, mobile);
            if (!checkIotAndMobileRs) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), "机柜编号或手机号格式错误");
                return R.error("机柜编号或手机号格式错误");
            }

            /**
             * 检查该用户是否存在订单
             */
            OrderEntity orderEntity = this.getById(orderId);
//            List<OrderEntity> orderEntities = this.list(new QueryWrapper<OrderEntity>().eq(FieldConstant.T_ORDER_TERMINAL_ID, terminalId).eq(FieldConstant.T_ORDER_MOBILE, mobile));
//            if (orderEntities.isEmpty()) {
//            log.info("path：{}，orderEntity：{}", getRequestUrl(), orderEntity);

            if (orderEntity == null) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), "不存在租赁该机柜的订单");
                return R.error("不存在租赁该机柜的订单");
            }
//            OrderEntity orderEntity = orderEntities.get(orderEntities.size() - 1);
            Integer comState = orderEntity.getComState();
            if (comState == 9) {
                log.info("path：{}，errMsg：{}", getRequestUrl(), "设备归还成功");
                return R.ok("设备归还").put("data", orderEntity);
            } else if (comState == 7) {
                log.info("path：{}，errMsg：{}", getRequestUrl(), "设备租赁中");
                return R.ok(201, "设备租赁中").put("data", orderEntity);
            } else if (comState == 10 || comState == 11) {
                log.info("path：{}，errMsg：{}", getRequestUrl(), "请完成欠费支付");
                return R.ok(202, "请完成欠费支付").put("data", orderEntity);
            } else if (comState == 12) {
                log.info("path：{}，errMsg：{}", getRequestUrl(), "交易已结束");
                return R.ok(203, "交易已结束").put("data", orderEntity);
            }
            return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }

    }

    @Override
    public R manualReturn(OrderEntity order) {
        try {
            Long id = order.getId();

            OrderEntity orderEntity = this.getById(id);
            if (orderEntity == null) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "该订单不存在", "所传id字段在数据库中未找到");
                return R.error("该订单不存在");
            }

            /**
             * 设置订单状态为 12结算支付成功 7已结算
             */
            orderEntity.setComState(12);
            orderEntity.setState(7);
            String memo = orderEntity.getMemo();
            if (!StringUtils.isEmpty(memo)) {
                orderEntity.setMemo(memo + ",手动归还");
            } else {
                orderEntity.setMemo("手动归还");
            }
            boolean updateRs = this.updateById(orderEntity);
            if (!updateRs) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "手动归还失败", "未知原因");
                return R.error("手动归还失败");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R manualCheckout(OrderEntity order) {
        try {
            Long id = order.getId();

            OrderEntity orderEntity = this.getById(id);
            if (orderEntity == null) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "该订单不存在", "所传id字段在数据库中未找到");
                return R.error("该订单不存在");
            }

            // 将fee设为paid_fee,同时修改state=7,update_time=当前时间，MEMO追加手动清费
            orderEntity.setPaidFee(orderEntity.getFee());
            orderEntity.setState(7);
            String memo = orderEntity.getMemo();
            if (!StringUtils.isEmpty(memo)) {
                orderEntity.setMemo(memo + ",手动清费");
            } else {
                orderEntity.setMemo("手动清费");
            }
            boolean updateRs = this.updateById(orderEntity);
            if (!updateRs) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "手动清费失败", "未知原因");
                return R.error("手动清费失败");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R getOrderStatus(Map<String, Object> params) {
        try {
            Long orderId = Convert.toLong(params.get("id"));

            // 校验订单是否存在
            OrderEntity orderEntity = this.getById(orderId);
            if (orderEntity == null) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), HttpStatusEnum.HTTP_ORDER_NO_EXIT.getMsg());
                return R.error(HttpStatusEnum.HTTP_ORDER_NO_EXIT.getCode(), HttpStatusEnum.HTTP_ORDER_NO_EXIT.getMsg());
            }

            Integer comState = orderEntity.getComState();
            Integer state = orderEntity.getState();

            if (comState == 12 && state == 7) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), HttpStatusEnum.HTTP_ORDER_OVER.getMsg());
                return R.ok(HttpStatusEnum.HTTP_ORDER_OVER.getCode(), HttpStatusEnum.HTTP_ORDER_OVER.getMsg());
            } else if ((comState == 7 && state == 4) || (comState == 10 && state == 6)) {
                log.warn("path：{}，errMsg：{}", getRequestUrl(), HttpStatusEnum.HTTP_ORDER_NO_OVER.getMsg());
                return R.ok(HttpStatusEnum.HTTP_ORDER_NO_OVER.getCode(), HttpStatusEnum.HTTP_ORDER_NO_OVER.getMsg());
            }
            return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }
}